package com.atguigu.gmall.list.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.atguigu.gmall.list.dao.GoodsRepository;
import com.atguigu.gmall.list.service.SearchService;
import com.atguigu.gmall.model.list.*;
import com.atguigu.gmall.model.product.BaseAttrInfo;
import com.atguigu.gmall.model.product.BaseCategoryView;
import com.atguigu.gmall.model.product.BaseTrademark;
import com.atguigu.gmall.model.product.SkuInfo;
import com.atguigu.gmall.product.feign.ProductFeignClient;
import com.sun.org.apache.xpath.internal.operations.Lte;
import org.apache.lucene.search.join.ScoreMode;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.common.text.Text;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.search.aggregations.Aggregation;
import org.elasticsearch.search.aggregations.AggregationBuilders;
import org.elasticsearch.search.aggregations.bucket.nested.ParsedNested;
import org.elasticsearch.search.aggregations.bucket.terms.ParsedLongTerms;
import org.elasticsearch.search.aggregations.bucket.terms.ParsedStringTerms;
import org.elasticsearch.search.aggregations.bucket.terms.Terms;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightField;
import org.elasticsearch.search.sort.SortOrder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import javax.swing.*;
import java.io.IOException;
import java.util.*;
import java.util.stream.Collectors;

import static com.sun.tools.doclint.Entity.lt;

@Service
public class SearchServiceImpl implements SearchService {
    @Autowired
    private GoodsRepository goodsRepository;
    @Autowired
    private ProductFeignClient productFeignClient;
    @Autowired
    private StringRedisTemplate stringRedisTemplate;
    @Autowired
    private RestHighLevelClient restHighLevelClient;
    /**
     * 上架商品
     *
     * @param skuId
     */
    @Override
    public void upperGoods(Long skuId) {
       //去product微服务查询sku 的详细信息
        SkuInfo skuInfo = productFeignClient.getSkuInfo(skuId);
        //判断
        if (skuInfo == null || skuInfo.getId() == null){
            throw  new RuntimeException("商品不存在，上架失败");
        }
        //将sku的信息转化为Goods类型
        Goods goods = convertSkuInfoToGoods(skuInfo);
        //保存数据到es中去
        goodsRepository.save(goods);
    }

    /**
     * 将skuinfo类型的数据转换为Goods类型的数据
     * @param skuInfo
     * @return
     */
    private Goods convertSkuInfoToGoods(SkuInfo skuInfo) {
        //初始化
        Goods goods = new Goods();
        //设置值
        goods.setId(skuInfo.getId());
        goods.setDefaultImg(skuInfo.getSkuDefaultImg());
        goods.setTitle(skuInfo.getSkuName());
        goods.setPrice(skuInfo.getPrice().doubleValue());
        goods.setCreateTime(new Date());
        goods.setTmId(skuInfo.getTmId());
        BaseTrademark baseTrademark = productFeignClient.getById(skuInfo.getTmId());
        goods.setTmName(baseTrademark.getTmName());
        goods.setTmLogoUrl(baseTrademark.getLogoUrl());
        //分类信息
        BaseCategoryView categoryView = productFeignClient.getCategoryView(skuInfo.getCategory3Id());
        goods.setCategory1Id(categoryView.getCategory1Id());
        goods.setCategory1Name(categoryView.getCategory1Name());
        goods.setCategory2Id(categoryView.getCategory2Id());
        goods.setCategory2Name(categoryView.getCategory2Name());
        goods.setCategory3Id(categoryView.getCategory3Id());
        goods.setCategory3Name(categoryView.getCategory3Name());
        //平台属性
        List<BaseAttrInfo> baseAttrInfos = productFeignClient.selectBaseAttrInfoBySku(skuInfo.getId());
        //转换数据
        List<SearchAttr> searchAttrs = baseAttrInfos.stream().map(attr ->{
            SearchAttr searchAttr = new SearchAttr();
            //补全数据
            searchAttr.setAttrId(attr.getId());
            searchAttr.setAttrName(attr.getAttrName());
            searchAttr.setAttrValue(attr.getAttrValueList().get(0).getValueName());

            //返回数据
            return searchAttr;
        }).collect(Collectors.toList());
        goods.setAttrs(searchAttrs);
        //商品的热度分数
        goods.setHotScore(0L);
        //包装完成
        return goods;
    }

    /**
     * 下架商品
     *
     * @param skuId
     */
    @Override
    public void lowerGoods(Long skuId) {
        //去es删除数据
        goodsRepository.deleteById(skuId);
    }

    /**
     * 更新热点
     *
     * @param skuId
     */
    @Override
    public void incrHotScore(Long skuId) {
        String hotKey = "hotScore";
        //每访问一次商品详情，对商品的热度+1
        Double aDouble = stringRedisTemplate.boundZSetOps(hotKey).incrementScore("sku:" + skuId, 1);
        //每访问10次同步一次es的数据
        if (aDouble % 10 == 0){
            Goods goods = goodsRepository.findById(skuId).get();
            //设置热度值
            goods.setHotScore(aDouble.longValue());
            //同步至es
            goodsRepository.save(goods);
        }
    }

    /**
     * 搜索列表
     *
     * @param searchParam
     * @return
     */
    @Override
    public SearchResponseVo search(SearchParam searchParam,Map<String,String> searchMap) {
        //初始化对象
        SearchResponseVo searchResponseVo = new SearchResponseVo();
        //构建查询条件
        SearchRequest searchRequest = new SearchRequest("goods_java0107");
        SearchSourceBuilder builder = buildQueryParam(searchParam,searchMap);
        searchRequest.source(builder);
        try {
            //执行查询
            SearchResponse searchResponse = restHighLevelClient.search(searchRequest,RequestOptions.DEFAULT);
            //解析结果
            searchResponseVo = getSearchResult(searchResponse);
            //补全页码和每页显示条数
            Integer pageNo = getPage(searchMap.get("pageNo"));
            searchResponseVo.setPageNo(pageNo);
            searchResponseVo.setPageSize(pageSize);
        } catch (Exception e) {
            e.printStackTrace();
        }
        //返回
        return searchResponseVo;
    }



    /**
     * 执行查询获取结果
     * @param searchResponse
     * @return
     */
    private SearchResponseVo getSearchResult(SearchResponse searchResponse) {
        //返回结果初始化
        SearchResponseVo searchResponseVo = new SearchResponseVo();
        //解析结果
        SearchHits hits = searchResponse.getHits();
        //获取迭代器
        Iterator<SearchHit> iterator = hits.iterator();
        //商品的集合对象
        List<Goods> goodsList = new ArrayList<>();
        //循环解析
        while (iterator.hasNext()){
            //获取每一条命中的数据
            SearchHit next = iterator.next();
            //取出数据
            String sourceAsString = next.getSourceAsString();
            //反序列化
            Goods goods = JSONObject.parseObject(sourceAsString, Goods.class);
            //获取高亮的数据
//            Map<String, HighlightField> highlightFields = next.getHighlightFields();
//            if (highlightFields != null && highlightFields.size() > 0){
//                Text[] titles = highlightFields.get("title").getFragments();
//                //非空判断
//                if (titles != null && titles.length > 0){
//                    String title = "";
//                    for (Text text : titles) {
//                        title += text;
//                    }
//                    goods.setTitle(title);
//                }
//
//            }
            Map<String, HighlightField> highlightFields = next.getHighlightFields();
            if (highlightFields != null && highlightFields.size() > 0){
                Text[] titles = highlightFields.get("title").getFragments();
                if (titles != null && titles.length >0){
                    String title = "";
                    for (Text text : titles) {
                        title += text;
                    }
                    goods.setTitle(title);
                }
            }
            goodsList.add(goods);
        }
        //获得聚合的结果
        Map<String, Aggregation> aggregationMap = searchResponse.getAggregations().asMap();
        //获取品牌的聚合结果
        List<SearchResponseTmVo> trackMarkList = getTrackMarkList(aggregationMap);
        searchResponseVo.setTrademarkList(trackMarkList);
        //获取平台属性的聚合结果
        List<SearchResponseAttrVo> attrInfoList = getAttrInfoList(aggregationMap);
        searchResponseVo.setAttrsList(attrInfoList);
        //将商品列表数据存入返回对象
        searchResponseVo.setGoodsList(goodsList);
        //设置总共多少条
        long totalHits = hits.totalHits;
        searchResponseVo.setTotal(totalHits);
        //返回结果
        return searchResponseVo;
    }

    /**
     * 获取平台属性的聚合结果
     * @param aggregationMap
     * @return
     */
    private List<SearchResponseAttrVo> getAttrInfoList(Map<String, Aggregation> aggregationMap) {
        //平台属性结果返回初始化
        List<SearchResponseAttrVo> searchResponseAttrVoList = new ArrayList<>();
        //获取所有的平台属性的聚合结果
        ParsedNested aggAttr = (ParsedNested) aggregationMap.get("aggAttr");
        //获取平台属性的id的聚合结果
        ParsedLongTerms aggAttrId = aggAttr.getAggregations().get("aggAttrId");
        for (Terms.Bucket bucket : aggAttrId.getBuckets()) {
            SearchResponseAttrVo searchResponseAttrVo = new SearchResponseAttrVo();
            //获取平台属性的Id
            Number keyAsNumber = bucket.getKeyAsNumber();
            searchResponseAttrVo.setAttrId(keyAsNumber.longValue());
            //获取子聚合中的平台属性名字
            ParsedStringTerms aggAttrName = bucket.getAggregations().get("aggAttrName");
            if (aggAttrName != null){
                searchResponseAttrVo.setAttrName(aggAttrName.getBuckets().get(0).getKeyAsString());
            }
            //平台属性的值
            List<String> values = new ArrayList<>();
            ParsedStringTerms aggAttrValue = bucket.getAggregations().get("aggAttrValue");
            for (Terms.Bucket aggAttrValueBucket : aggAttrValue.getBuckets()) {
                values.add(aggAttrValueBucket.getKeyAsString());
            }
            //将所有的平台属性值存入返回对象
            searchResponseAttrVo.setAttrValueList(values);
            searchResponseAttrVoList.add(searchResponseAttrVo);
        }
        return searchResponseAttrVoList;
    }

    /**
     * 获得品牌的聚合结果
     * @param aggregationMap
     * @return
     */
    private List<SearchResponseTmVo> getTrackMarkList(Map<String, Aggregation> aggregationMap) {
        List<SearchResponseTmVo> trademarkList = new ArrayList<>();
        //获取品牌id的聚合结果
        ParsedLongTerms parsedLongTerms  = (ParsedLongTerms) aggregationMap.get("aggTmId");
        //遍历获取
        for (Terms.Bucket bucket : parsedLongTerms.getBuckets()) {
            SearchResponseTmVo searchResponseTmVo = new SearchResponseTmVo();
            //获取品牌的id
            String tmId = bucket.getKeyAsString();
            searchResponseTmVo.setTmId(Long.parseLong(tmId));
            //获取品牌的名字和品牌的logo
            ParsedStringTerms aggTmName = bucket.getAggregations().get("aggTmName");
            if (aggTmName != null){
                String tmName = aggTmName.getBuckets().get(0).getKeyAsString();
                searchResponseTmVo.setTmName(tmName);
            }
            ParsedStringTerms aggTmLogoUrl = bucket.getAggregations().get("aggTmLogoUrl");
            if (aggTmLogoUrl != null){
                String tmLogoUrl = aggTmLogoUrl.getBuckets().get(0).getKeyAsString();
                searchResponseTmVo.setTmLogoUrl(tmLogoUrl);
            }
            //列表保存
            trademarkList.add(searchResponseTmVo);
        }
        return trademarkList;
    }
    /**
     * 构建查询条件
     * @param searchParam
     * @return
     */
    @Value("${page.size}")
    private Integer pageSize;
    private SearchSourceBuilder buildQueryParam(SearchParam searchParam,Map<String,String> searchMap) {
        //参数校验
        String keyword = searchParam.getKeyword();
        Long category3Id = searchParam.getCategory3Id();
        if (StringUtils.isEmpty(keyword) && category3Id == null){
            throw new RuntimeException("参数错误！");
        }
        //构造条件组合
        SearchSourceBuilder builder = new SearchSourceBuilder();
        //构建组合查询对象
        BoolQueryBuilder boolQueryBuilder = new BoolQueryBuilder();
        //关键字查询条件
        if (!StringUtils.isEmpty(keyword)){
            boolQueryBuilder.must(QueryBuilders.matchQuery("title",keyword));
        }
        //三级分类查询条件
        if (category3Id != null){
            boolQueryBuilder.must(QueryBuilders.termQuery("category3Id",category3Id));
        }
        //品牌的查询条件: 1:华为
        String trademark = searchParam.getTrademark();
        if (!StringUtils.isEmpty(trademark)){
            //切分
            String[] split = trademark.split(":");
            if (split != null && split.length > 0){
                boolQueryBuilder.must(QueryBuilders.termQuery("tmId",split[0]));
            }
        }
        //平台属性进行查询
        for (Map.Entry<String, String> entry : searchMap.entrySet()) {
            String key = entry.getKey();
            if (key.startsWith("prop_")){
                String value = entry.getValue();
                //切分23:4G
                String[] split = value.split(":");
                if (split !=null && split.length > 1){
                    BoolQueryBuilder subQuery = QueryBuilders.boolQuery();
                    //平台属性的Id相等
                    subQuery.must(QueryBuilders.termQuery("attrs.attrId",split[0]));
                    //平台属性的值相等
                    subQuery.must(QueryBuilders.termQuery("attrs.attrValue",split[1]));
                    //构建nested类型的匹配
                    boolQueryBuilder.must(QueryBuilders.nestedQuery("attrs",subQuery, ScoreMode.None));
                }
            }
        }
        //价格查询
        String price = searchMap.get("price");
        if (!StringUtils.isEmpty(price)){
            String[] split = price.split("-");
            if (split != null && split.length > 0){
                boolQueryBuilder.must(QueryBuilders.rangeQuery("price").gte(split[0]));
                if (split[1] !=null){
                    boolQueryBuilder.must(QueryBuilders.rangeQuery("price").lt(split[1]));
                }
            }

        }
        //条件构建
        builder.query(boolQueryBuilder);
        //构建品牌聚合查询
        builder.aggregation(
                AggregationBuilders.terms("aggTmId").field("tmId")
                        .subAggregation(AggregationBuilders.terms("aggTmName").field("tmName")
                        .subAggregation(AggregationBuilders.terms("aggTmLogoUrl").field("tmLogoUrl"))).size(10000));
        //构建平台属性聚合查询
        builder.aggregation(
                AggregationBuilders.nested("aggAttr" ,"attrs")
                        .subAggregation(
                                AggregationBuilders.terms("aggAttrId").field("attrs.attrId")
                                        .subAggregation(AggregationBuilders.terms("aggAttrName").field("attrs.attrName"))
                                        .subAggregation(AggregationBuilders.terms("aggAttrValue").field("attrs.attrValue"))
                        )
        );
        Integer pageNo = getPage(searchMap.get("pageNo"));
        //计算分页信息
        Integer start = (pageNo - 1) * pageSize;
        builder.from(start);
        builder.size(pageSize);
        //排序实现:order =1:hotScore:Asc
        String order = searchParam.getOrder();
        if (!StringUtils.isEmpty(order)){
            String[] split = order.split(":");
            if (split != null && split.length > 2){
                switch (Integer.parseInt(split[0])){
                    case 1:
                        builder.sort("hotScore", SortOrder.valueOf(split[2].toUpperCase()));
                        break;
                    case 2:
                        builder.sort("price",SortOrder.valueOf(split[2].toUpperCase()));
                        break;
                    case 3:
                        builder.sort("createTime",SortOrder.valueOf(split[2].toUpperCase()));
                        break;
                }
            }
        }else {
            builder.sort("hotScore",SortOrder.DESC);
        }
        //设置高亮条件
        HighlightBuilder highlightBuilder = new HighlightBuilder();
        //设置高亮域
        highlightBuilder.field("title");
        highlightBuilder.preTags("<em style='color:red'>");
        highlightBuilder.postTags("</em>");
        builder.highlighter(highlightBuilder);
        //返回构建条件
        return builder;
    }

    /**
     * 页码处理
     * @param pageNo
     * @return
     */
    private Integer getPage(String pageNo) {
        try {
            return Integer.parseInt(pageNo);
        } catch (Exception e) {
            return 1;
        }
    }



}
